import math    
import scipy.stats as stats    
    
class SampleSizeCalculator:    
    def __init__(self, nominal_defect_rate, allowed_error, min_sample_size=10):    
        self.nominal_defect_rate = nominal_defect_rate    
        self.allowed_error = allowed_error    
        self.min_sample_size = min_sample_size    
    
    def calculate_minimum_sample_size(self, z_alpha):    
        """    
        使用Cochran公式计算样本量的最小要求值    
    
        :param z_alpha: 标准正态分布的临界值（根据置信水平）    
        :return: 样本量n，至少为min_sample_size    
        """    
        if not (0 <= self.nominal_defect_rate <= 1):    
            raise ValueError("标称次品率必须在0到1之间")    
            
        # 使用Cochran公式计算样本量  
        n = (z_alpha * math.sqrt(self.nominal_defect_rate * (1 - self.nominal_defect_rate)) / self.allowed_error)**2 + z_alpha**2    
        return max(math.ceil(n), self.min_sample_size)    
    
class HypothesisTester:    
    def __init__(self, alpha):    
        self.alpha = alpha    
    
    def test(self, sample_size, nominal_defect_rate, observed_defective_rate):    
        """    
        进行假设检验，检验样本次品率是否显著不同于标称次品率    
    
        :param sample_size: 样本量    
        :param nominal_defect_rate: 标称次品率（假设的次品率）    
        :param observed_defective_rate: 样本中的次品率    
        :return: 布尔值，表示是否拒绝零假设    
        """    
        if not (0 < observed_defective_rate < 1):    
            raise ValueError("观测到的次品率必须为(0, 1)区间内的数")    
            
        if sample_size <= 0:    
            raise ValueError("样本量必须为正数")    
            
        # 计算标准误差    
        std_error = math.sqrt(observed_defective_rate * (1 - observed_defective_rate) / sample_size)    
    
        # 计算检验统计量    
        z = (observed_defective_rate - nominal_defect_rate) / std_error    
    
        # 获取双侧检验的临界z值    
        z_critical = stats.norm.ppf(1 - self.alpha / 2)    
    
        # 根据双侧检验的z值判断是否拒绝零假设    
        return abs(z) > z_critical    
    
# 已知参数    
nominal_defect_rate = 0.10  # 标称次品率    
allowed_error = 0.02  # 允许误差    
min_sample_size = 10  # 最小样本量    
alpha_95 = 0.05  # 95%的显著性水平    
alpha_90 = 0.10  # 90%的显著性水平    
    
# 创建样本量计算器实例    
calculator = SampleSizeCalculator(nominal_defect_rate, allowed_error, min_sample_size)    
    
# 获取对应的z值    
z_95 = stats.norm.ppf(1 - alpha_95 / 2)    
z_90 = stats.norm.ppf(1 - alpha_90 / 2)    
    
# 计算样本量    
sample_size_95 = calculator.calculate_minimum_sample_size(z_95)    
sample_size_90 = calculator.calculate_minimum_sample_size(z_90)    
    
# 输出结果    
print(f"95%置信水平下的样本量: {sample_size_95}")    
print(f"90%置信水平下的样本量: {sample_size_90}")    
    
# 假设观测到的次品率    
observed_defective_rate = 0.12    
    
# 创建假设检验器实例    
tester_95 = HypothesisTester(alpha_95)    
tester_90 = HypothesisTester(alpha_90)    
    
# 进行假设检验    
try:    
    reject_null_95 = tester_95.test(sample_size_95, nominal_defect_rate, observed_defective_rate)    
    reject_null_90 = tester_90.test(sample_size_90, nominal_defect_rate, observed_defective_rate)    
    print(f"在95%置信水平下，是否拒绝零假设: {reject_null_95}")    
    print(f"在90%置信水平下，是否拒绝零假设: {reject_null_90}")    
except ValueError as e:    
    print(e)


